package com.starview.star.operators.hash.runtime;

import java.util.Iterator;
import java.util.Map.Entry;

import com.starview.platform.data.EvaluationException;
import com.starview.platform.data.IFunction;
import com.starview.platform.data.IMap;
import com.starview.platform.data.IValue;
import com.starview.platform.data.type.IType;
import com.starview.platform.data.type.Refresher;
import com.starview.platform.data.type.TypeUtils;
import com.starview.platform.data.type.TypeVar;
import com.starview.star.operators.CafeEnter;
import com.starview.star.operators.arrays.runtime.ArrayOps;

public class HashTreeIterable
{

  public static class HashIterate implements IFunction
  {
    public static final String name = "__hash_iterate";

    @CafeEnter
    public static IValue enter(IMap hash, IFunction iter, IValue state) throws EvaluationException
    {
      for (Iterator<Entry<IValue, IValue>> it = hash.iterator(); it.hasNext() && !ArrayOps.isAllDone(state);) {
        Entry<IValue, IValue> entry = it.next();
        state = iter.enter(entry.getValue(), state);
      }

      return state;
    }

    @Override
    public IValue enter(IValue... args) throws EvaluationException
    {
      return enter((IMap) args[0], (IFunction) args[1], args[2]);
    }

    @Override
    public IType getType()
    {
      return type();
    }

    public static IType type()
    {
      // %k~%v~%s~(map of (%k,%v),(%v,%s)=>%s,%s) => %s

      TypeVar k = new TypeVar();
      TypeVar v = new TypeVar();
      TypeVar s = new TypeVar();

      IType mapType = TypeUtils.hashType(k, v);

      IType funType = TypeUtils.functionType(mapType, TypeUtils.functionType(v, s, s), s, s);
      return Refresher.generalize(funType);
    }
  }

  public static class HashIxIterate implements IFunction
  {
    public static final String name = "__hash_ix_iterate";

    @CafeEnter
    public static IValue enter(IMap hash, IFunction iter, IValue state) throws EvaluationException
    {
      for (Iterator<Entry<IValue, IValue>> it = hash.iterator(); it.hasNext() && !ArrayOps.isAllDone(state);) {
        Entry<IValue, IValue> entry = it.next();
        state = iter.enter(entry.getKey(), entry.getValue(), state);
      }

      return state;
    }

    @Override
    public IValue enter(IValue... args) throws EvaluationException
    {
      return enter((IMap) args[0], (IFunction) args[1], args[2]);
    }

    @Override
    public IType getType()
    {
      return type();
    }

    public static IType type()
    {
      // %k~%v~%s~(map of (%k,%v),(%k,%v,%s)=>%s,%s) => %s

      TypeVar k = new TypeVar();
      TypeVar v = new TypeVar();
      TypeVar s = new TypeVar();

      IType mapType = TypeUtils.hashType(k, v);

      IType funType = TypeUtils.functionType(mapType, TypeUtils.functionType(k, v, s, s), s, s);
      return Refresher.generalize(funType);
    }
  }
}
